//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package data_anno_task_api_serv

import (
	"context"
	"strings"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/data_anno_dao"
	"atomgit.com/openlinksaas/api-server/dao/fs_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/data_anno_task_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *DataAnnoTaskApiImpl) SetTaskCount(ctx context.Context, req *data_anno_task_api.SetTaskCountRequest) (*data_anno_task_api.SetTaskCountResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查信息是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.AnnoProjectId, req.ProjectId)
	if err != nil {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_ANNO_PROJECT,
			ErrMsg: "标注项目不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO) {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_ANNO_PROJECT,
			ErrMsg: "标注项目不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查项目成员是否存在
	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_MEMBER,
			ErrMsg: "项目成员不存在",
		}, nil
	}
	//检查标注项目是否存在
	exist, err = data_anno_dao.AnnoProjectDao.Exist(ctx, req.ProjectId, req.AnnoProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_ANNO_PROJECT,
			ErrMsg: "标注项目不存在",
		}, nil
	}
	//检查标注成员是否存在
	exist, err = data_anno_dao.AnnoMemberDao.Exist(ctx, req.AnnoProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &data_anno_task_api.SetTaskCountResponse{
			Code:   data_anno_task_api.SetTaskCountResponse_CODE_NO_MEMBER,
			ErrMsg: "标注成员不存在",
		}, nil
	}

	//列出所有resource
	resourceItemList, err := data_anno_dao.ResourceDao.ListByTaskCount(ctx, req.AnnoProjectId)
	if err != nil {
		return nil, err
	}
	//列出我当前的resource
	myResourceIdList, err := data_anno_dao.AnnoTaskDao.DistinctResourceByMember(ctx, req.AnnoProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	resourceIdMap := map[string]bool{}
	for _, resourceId := range myResourceIdList {
		resourceIdMap[resourceId] = true
	}
	//插入不存在的任务
	for _, resourceItem := range resourceItemList {
		if resourceIdMap[resourceItem.ResourceId] {
			continue
		}
		count, err := data_anno_dao.AnnoTaskDao.CountByMember(ctx, req.AnnoProjectId, req.MemberUserId, false, false)
		if err != nil {
			return nil, err
		}
		if count >= req.TaskCount {
			break
		}
		apiImpl.addTask(ctx, req, resourceItem.ResourceId)
	}

	return &data_anno_task_api.SetTaskCountResponse{
		Code: data_anno_task_api.SetTaskCountResponse_CODE_OK,
	}, nil
}

func (apiImpl *DataAnnoTaskApiImpl) addTask(ctx context.Context, req *data_anno_task_api.SetTaskCountRequest, resourceId string) {
	dbSess, err := dao.StartSession()
	if err != nil {
		return
	}
	defer dao.EndSession(dbSess)

	dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = data_anno_dao.AnnoTaskDao.Insert(sessCtx, &data_anno_dao.TaskInfoDbItem{
			AnnoProjectId: req.AnnoProjectId,
			MemberUserId:  req.MemberUserId,
			ResourceId:    resourceId,
			Done:          false,
			TimeStamp:     time.Now().UnixNano() / 1e6,
		})
		if err != nil {
			return nil, err
		}
		//更新member上的taskCount
		count, err := data_anno_dao.AnnoTaskDao.CountByMember(sessCtx, req.AnnoProjectId, req.MemberUserId, false, false)
		if err != nil {
			return nil, err
		}
		err = data_anno_dao.AnnoMemberDao.UpdateTaskCount(sessCtx, req.AnnoProjectId, req.MemberUserId, count)
		if err != nil {
			return nil, err
		}
		//更新resource上的taskCount
		count, err = data_anno_dao.AnnoTaskDao.CountByResource(sessCtx, req.AnnoProjectId, resourceId)
		if err != nil {
			return nil, err
		}
		err = data_anno_dao.ResourceDao.UpdateTaskCount(sessCtx, resourceId, req.AnnoProjectId, count)
		if err != nil {
			return nil, err
		}
		//更新标注项目上的taskCount
		count, err = data_anno_dao.AnnoTaskDao.CountByAnnoProject(sessCtx, req.AnnoProjectId, false, false)
		if err != nil {
			return nil, err
		}
		err = data_anno_dao.AnnoProjectDao.UpdateAllTaskCount(sessCtx, req.ProjectId, req.AnnoProjectId, count)
		if err != nil {
			return nil, err
		}

		return nil, nil
	})
}

func (apiImpl *DataAnnoTaskApiImpl) ListTask(ctx context.Context, req *data_anno_task_api.ListTaskRequest) (*data_anno_task_api.ListTaskResponse, error) {
	emptyList := []*data_anno_task_api.TaskInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &data_anno_task_api.ListTaskResponse{
			Code:     data_anno_task_api.ListTaskResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			InfoList: emptyList,
		}, nil
	}
	if req.MemberUserId == "" {
		req.MemberUserId = sessionItem.UserId
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &data_anno_task_api.ListTaskResponse{
			Code:     data_anno_task_api.ListTaskResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			InfoList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &data_anno_task_api.ListTaskResponse{
			Code:     data_anno_task_api.ListTaskResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			InfoList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	if sessionItem.UserId != req.MemberUserId {
		entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.AnnoProjectId, req.ProjectId)
		if err != nil {
			return &data_anno_task_api.ListTaskResponse{
				Code:     data_anno_task_api.ListTaskResponse_CODE_NO_ANNO_PROJECT,
				ErrMsg:   "标注项目不存在",
				InfoList: emptyList,
			}, nil
		}
		if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO) {
			return &data_anno_task_api.ListTaskResponse{
				Code:     data_anno_task_api.ListTaskResponse_CODE_NO_ANNO_PROJECT,
				ErrMsg:   "标注项目不存在",
				InfoList: emptyList,
			}, nil
		}

		hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

		if !hasUpdatePerm {
			return &data_anno_task_api.ListTaskResponse{
				Code:     data_anno_task_api.ListTaskResponse_CODE_NO_PERMISSION,
				ErrMsg:   "没有权限",
				InfoList: emptyList,
			}, nil
		}
	}

	//检查标注项目是否存在
	exist, err := data_anno_dao.AnnoProjectDao.Exist(ctx, req.ProjectId, req.AnnoProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &data_anno_task_api.ListTaskResponse{
			Code:     data_anno_task_api.ListTaskResponse_CODE_NO_ANNO_PROJECT,
			ErrMsg:   "标注项目不存在",
			InfoList: emptyList,
		}, nil
	}
	//检查标注成员是否存在
	exist, err = data_anno_dao.AnnoMemberDao.Exist(ctx, req.AnnoProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &data_anno_task_api.ListTaskResponse{
			Code:     data_anno_task_api.ListTaskResponse_CODE_NO_MEMBER,
			ErrMsg:   "标注项目不存在",
			InfoList: emptyList,
		}, nil
	}

	taskItemList, err := data_anno_dao.AnnoTaskDao.ListByMember(ctx, req.AnnoProjectId, req.MemberUserId, req.FilterByDone, req.Done)
	if err != nil {
		return nil, err
	}
	//加载resource
	resourceIdList := []string{}
	for _, taskItem := range taskItemList {
		resourceIdList = append(resourceIdList, taskItem.ResourceId)
	}
	resourceItemList, err := data_anno_dao.ResourceDao.ListById(ctx, req.AnnoProjectId, resourceIdList)
	if err != nil {
		return nil, err
	}
	resourceItemMap := map[string]*data_anno_dao.ResourceInfoDbItem{}
	for _, resourceItem := range resourceItemList {
		resourceItemMap[resourceItem.ResourceId] = resourceItem
	}
	//计算文件结尾
	fileIdList := []string{}
	for _, resourceItem := range resourceItemList {
		if resourceItem.StoreAsFile {
			fileIdList = append(fileIdList, resourceItem.Content)
		}
	}
	fileItemList, err := fs_dao.FsFileDao.ListById(ctx, projectItem.DataAnnoFsId, fileIdList)
	if err != nil {
		return nil, err
	}
	fileExtMap := map[string]string{}
	for _, fileItem := range fileItemList {
		pos := strings.LastIndex(fileItem.FileName, ".")
		if pos != -1 {
			fileExtMap[fileItem.FileId] = fileItem.FileName[pos+1:]
		}
	}
	//生产结果
	infoList := []*data_anno_task_api.TaskInfo{}
	for _, taskItem := range taskItemList {
		info := taskItem.ToTaskInfo()
		resourceItem, ok := resourceItemMap[taskItem.ResourceId]
		if ok {
			info.Content = resourceItem.Content
			info.StoreAsFile = resourceItem.StoreAsFile
			if resourceItem.StoreAsFile {
				info.FileExt = fileExtMap[resourceItem.Content]
			}
			infoList = append(infoList, info)
		}
	}
	return &data_anno_task_api.ListTaskResponse{
		Code:     data_anno_task_api.ListTaskResponse_CODE_OK,
		InfoList: infoList,
	}, nil
}
